﻿using System;
using System.Collections.Generic;
using EnvDTE;
using EnvDTE80;

namespace MEFAddin.Adapters
{
    public class CommandAdapter : MEFAddin.Adapters.ICommandAdapter
    {
        private AddInContext _AddInContext;

        private ILoggingAdapter _LoggingAdapter;

        private IWindowAdapter _WindowAdapter;

        private CommandEvents _CommandEvents;

        private dynamic _MenuCommandBar = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="CommandAdapter"/> class.
        /// </summary>
        /// <param name="addInContext">The add in context.</param>
        /// <param name="loggingAdapter">The logging adapter.</param>
        /// <param name="windowAdapter">The window adapter.</param>
        public CommandAdapter(AddInContext addInContext, ILoggingAdapter loggingAdapter, IWindowAdapter windowAdapter)
        {
            this._AddInContext = addInContext;
            this._LoggingAdapter = loggingAdapter;
            this._WindowAdapter = windowAdapter;
            this._CommandEvents = _AddInContext.ApplicationObject.Events.get_CommandEvents("{52692960-56BC-4989-B5D3-94C47A513E8D}", 1);
        }

        /// <summary>
        /// Gets the command bars.
        /// </summary>
        public dynamic CommandBars
        {
            get
            {
                return this._AddInContext.AddInInstance.DTE.CommandBars;
            }
        }

        /// <summary>
        /// Gets the commands.
        /// </summary>
        public Commands Commands
        {
            get
            {
                return this._AddInContext.AddInInstance.DTE.Commands;
            }
        }

        /// <summary>
        /// Gets the command events.
        /// </summary>
        public CommandEvents CommandEvents
        {
            get
            {
                return _CommandEvents;
            }
        }

        /// <summary>
        /// Creates the command bar.
        /// </summary>
        /// <param name="menuName">Name of the menu.</param>
        /// <returns></returns>
        public dynamic CreateCommandBar(string menuName)
        {
            try
            {
                return ReAddCommandBar(GetToolsMenuControl(), menuName);
            }
            catch (Exception e)
            {
                this._LoggingAdapter.LogError("Error AddInController.CreateCommandBar: " + e.ToString());
                throw;
            }
        }

        /// <summary>
        /// Adds the command.
        /// </summary>
        /// <param name="Bar">The bar.</param>
        /// <param name="name">The name.</param>
        /// <param name="text">The text.</param>
        /// <param name="toolTip">The tool tip.</param>
        /// <param name="imageIndex">Index of the image.</param>
        /// <returns></returns>
        public dynamic AddCommand(dynamic Bar, string name, string text, string toolTip, int imageIndex)
        {
            try
            {
                RemoveCommands(name);
                var cmd = AddNamedCommand(name, text, toolTip, 13);
                cmd.AddControl(Bar, 1);
                return cmd;
            }
            catch (Exception e)
            {
                this._LoggingAdapter.LogError("Error AddInController.AddCommand: " + e.ToString());
                throw;
            }
        }

        /// <summary>
        /// Adds the named command.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="buttonText">The button text.</param>
        /// <param name="toolTip">The tool tip.</param>
        /// <param name="ImageId">The image id.</param>
        /// <returns></returns>
        public dynamic AddNamedCommand(string name, string buttonText, string toolTip, int ImageId)
        {
            try
            {
                object[] contextGUIDS = new object[] { };
                int commandStatus = (int)vsCommandStatus.vsCommandStatusSupported +
                    (int)vsCommandStatus.vsCommandStatusEnabled;
                int commandStyle = (int)vsCommandStyle.vsCommandStylePictAndText;

                dynamic commands = _AddInContext.AddInInstance.DTE.Commands;
                dynamic cmdResult = commands.AddNamedCommand2(_AddInContext.AddInInstance, name,
                    buttonText, toolTip, true, ImageId,
                    ref contextGUIDS,
                    commandStatus,
                    commandStyle,
                    vsCommandControlType.vsCommandControlTypeButton);
                return cmdResult;
            }
            catch (Exception x)
            {
                this._LoggingAdapter.LogError("AddNamedCommand() Error: " + x.Message);
                throw;
            }
        }

        /// <summary>
        /// Finds the commands.
        /// </summary>
        /// <param name="commandName">Name of the command.</param>
        /// <returns></returns>
        private List<Command> FindCommands(string commandName)
        {
            try
            {
                var commandItems = new List<Command>();

                foreach (Command cmd in _AddInContext.AddInInstance.DTE.Commands)
                {
                    if (cmd.Name.ToString().Contains(commandName))
                    {
                        commandItems.Add(cmd);
                    }
                }
                return commandItems;
            }
            catch (Exception e)
            {
                this._LoggingAdapter.LogError("Error AddInController.FindCommands: " + e.ToString());
                throw;
            }
        }

        /// <summary>
        /// Gets the tools menu control.
        /// </summary>
        /// <returns></returns>
        private dynamic GetToolsMenuControl()
        {
            var tools = GetMenuCommandBar().Controls["Tools"];
            if (tools == null)
                throw new Exception("tools is null");
            return tools;
        }

        /// <summary>
        /// Gets the command bars.
        /// </summary>
        /// <returns></returns>
        private dynamic GetCommandBars()
        {
            return _AddInContext.AddInInstance.DTE.CommandBars;
        }

        /// <summary>
        /// Adds the command bar.
        /// </summary>
        /// <param name="menu">The menu.</param>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        private dynamic AddCommandBar(dynamic menu, string name)
        {
            return GetCommands().AddCommandBar(name,
                    vsCommandBarType.vsCommandBarTypeMenu, menu.CommandBar);
        }

        /// <summary>
        /// Res the add command bar.
        /// </summary>
        /// <param name="menu">The menu.</param>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        private dynamic ReAddCommandBar(dynamic menu, string name)
        {
            RemoveCommandBarControls(menu, name);
            return AddCommandBar(menu, name);
        }

        /// <summary>
        /// Finds the command bar controls.
        /// </summary>
        /// <param name="menu">The menu.</param>
        /// <param name="commandBarName">Name of the command bar.</param>
        /// <returns></returns>
        private List<dynamic> FindCommandBarControls(dynamic menu, string commandBarName)
        {
            var menuItems = new List<dynamic>();
            foreach (var control in menu.CommandBar.Controls)
            {
                if (control.Caption.ToString().Contains(commandBarName))
                {
                    menuItems.Add(control);
                }
            }
            return menuItems;
        }

        /// <summary>
        /// Removes the command bar controls.
        /// </summary>
        /// <param name="menu">The menu.</param>
        /// <param name="commandBarName">Name of the command bar.</param>
        private void RemoveCommandBarControls(dynamic menu, string commandBarName)
        {
            foreach (var control in FindCommandBarControls(menu, commandBarName))
            {
                control.Delete();
            }
        }

        /// <summary>
        /// Gets the commands.
        /// </summary>
        /// <returns></returns>
        private Commands GetCommands()
        {
            return _AddInContext.AddInInstance.DTE.Commands;
        }

        /// <summary>
        /// Removes the commands.
        /// </summary>
        /// <param name="commandName">Name of the command.</param>
        private void RemoveCommands(string commandName)
        {
            try
            {
                var commandItems = FindCommands(commandName);
                foreach (Command cmd in commandItems)
                {
                    try
                    {
                        this._LoggingAdapter.LogMessage("deleting:" + cmd.Name);
                        cmd.Delete();
                    }
                    catch (Exception e)
                    {
                        this._LoggingAdapter.LogError("Error AddInController.RemoveCommands.Delete: " + e.ToString());
                        //throw;
                    }
                }
            }
            catch (Exception e)
            {
                this._LoggingAdapter.LogError("Error AddInController.RemoveCommands: " + e.ToString());
                throw;
            }
        }


        /// <summary>
        /// Gets the menu command bar.
        /// </summary>
        /// <returns></returns>
        private dynamic GetMenuCommandBar()
        {
            if (_MenuCommandBar == null)
            {
                _MenuCommandBar = GetCommandBars()["MenuBar"];
            }
            if (_MenuCommandBar == null)
                throw new Exception("Menu bar is null");

            return _MenuCommandBar;
        }
    }
}
